package com.youlai.eng.service;

import cn.hutool.core.lang.Assert;
import com.youlai.common.base.PageBean;
import com.youlai.eng.entity.EngBill2Entity;
import com.youlai.eng.entity.EngItemEntity;
import com.youlai.eng.query.PageQuery;
import com.youlai.eng.repository.EngBill2Repository;
import com.youlai.eng.repository.EngItemRepository;
import com.youlai.common.exception.BusinessException;
import com.youlai.common.result.PageResult;
import com.youlai.utils.DateUtils;
import com.youlai.system.util.SecurityUtils;
import com.youlai.core.security.model.SysUserDetails;
import com.youlai.system.service.SysDictService;
import jakarta.annotation.Resource;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class EngBill2Service {
    @Autowired
    private EngBill2Repository repository;

    @PersistenceContext
    private EntityManager em;

    public EntityManager getEntityManager() {
        return em;
    }

    @Resource
    SysDictService sysDictService;

    /**
     * 分页查询列表
     *
     * @param queryParams
     * @return
     */
    public PageResult<EngBill2Entity> getPageByHql(PageQuery queryParams) {
        // 查询参数
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        String keywords = queryParams.getKeywords();

        // 动态拼接sql
        String hql = "from EngBill2Entity where  deleted = 0  ";
        if (StringUtils.isNotEmpty(keywords)  ) {
            hql += " and (" +
                    " parentItemNo like '%" + keywords +"%' " +
                    ") ";
        }
        if (StringUtils.isNotEmpty(queryParams.getChildItemNo())  ) {
            hql +=  "  and childItemNoEntity.itemNo like '%" + queryParams.getChildItemNo() +"%' ";
        }
        DateUtils.toDatabaseFormat(queryParams, "startUpdateTime", "endUpdateTime");
        if (StringUtils.isNotEmpty(queryParams.getStartUpdateTime())) {
            hql += " and DATE_FORMAT(updateTime, '%Y-%m-%d %H:%i:%s') >=  '"+ queryParams.getStartUpdateTime()  +"'  ";
        }
        if (StringUtils.isNotEmpty(queryParams.getEndUpdateTime())) {
            hql += " and DATE_FORMAT(updateTime, '%Y-%m-%d %H:%i:%s') <=  '"+ queryParams.getEndUpdateTime()  +"'  ";
        }

        // 查询数据
        PageBean pageBean = new PageBean();
        pageBean.setPage(pageNum);
        pageBean.setRows(pageSize);
        if(queryParams.getIsMultilayer()!=null && queryParams.getIsMultilayer() ==1) { //多层BOM不分页
            pageBean.setPagination(false);
        }
        if(pageBean !=null && pageBean.isPagination()) {
            String countHql = getCountHql(hql);
            Query countQuery = em.createQuery(countHql);
            pageBean.setTotal(countQuery.getSingleResult().toString());

            hql += " order by  updateTime desc";
            Query query = em.createQuery(hql);
            query.setFirstResult(pageBean.getStartIndex());
            query.setMaxResults(pageBean.getRows());
            List<EngBill2Entity> list = query.getResultList();
            for(EngBill2Entity o:list) {
                //查询父货号
                EngItemEntity engItemEntity = engItemRepository.findTopByItemNoAndDeleted(o.getParentItemNo(),0);
                if(engItemEntity!=null) {
                    o.setParentItemName(engItemEntity.getItemName());
                }
            }

            PageResult page = PageResult.success(list, pageBean.getTotal());
            return page;
        }
        return null;
    }

    /**
       这里的one代表的是初始第一根柱子
       two代表的是中转盘子的第二根柱子
       three代表的是目的柱子
    */
    public  void getChildBillList( List<EngBill2Entity> list,List<EngBill2Entity> last,int level){
        level ++;
        if(list!=null && list.size()==0){
            return;
        }else{
            for(EngBill2Entity o1:list) {
                o1.setLevel(level+"");
                last.add(o1);
                String hql="";
                if (StringUtils.isNotEmpty(o1.getItemNoEntity().getItemNo())) {
                    hql = "from EngBill2Entity where  deleted = 0  ";
                    hql += " and parentItemNo = '" + o1.getItemNoEntity().getItemNo() + "' ";
                }
                Query query = em.createQuery(hql);
                query.setFirstResult(0);
                query.setMaxResults(100);
                list = query.getResultList();
                getChildBillList(list,last,level);
            }
        }
    }


    /**
     * 函数式接口 T -> bollean
     * @param keyExtractor
     * @param <T>
     * @return
     */
    public static <T> java.util.function.Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>(16);
        return t -> map.putIfAbsent(keyExtractor.apply(t),Boolean.TRUE) == null;
    }

    public String getCountHql(String hql) {
        //hql = "from Book where bookName like :bookName"
        //hql = " select * from new Book where(bid,bookName) where bookName like :bookName"
        int index = hql.toUpperCase().indexOf("FROM");
        return "select count(1) " +hql.substring(index);
    }

    @Autowired
    private EngItemRepository engItemRepository;

    public void save(EngBill2Entity entity){
        // 校验员工编号是否存在
        String parentItemNo = entity.getParentItemNo();
        String childItemNo = entity.getItemNoEntity().getItemNo();
        String ct = entity.getCt();
        Specification<EngBill2Entity> spec  = (Root<EngBill2Entity> root, CriteriaQuery<?> cq, CriteriaBuilder cb) -> {
            Predicate predicate = cb.and(cb.equal(root.get("parentItemNo"), parentItemNo));
            predicate = cb.and(cb.equal(root.get("itemNo"), childItemNo),predicate);
            predicate = cb.and(cb.equal(root.get("ct"), ct),predicate);
            return predicate;
        };
        long count = repository.count(spec);
        Assert.isTrue(count == 0, "父货号+子类+子货号 已存在");

        //处理关联字段 childItemNo
        Specification<EngItemEntity> spec2  = (Root<EngItemEntity> root, CriteriaQuery<?> cq, CriteriaBuilder cb) -> {
            Predicate predicate = cb.and(cb.equal(root.get("itemNo"), childItemNo));
            predicate = cb.and(cb.equal(root.get("status"), 1),predicate);
            predicate = cb.and(cb.equal(root.get("deleted"), 0),predicate);
            return predicate;
        };
        Optional<EngItemEntity> optional2 = engItemRepository.findOne(spec2);
        if(optional2.isPresent()) {
            EngItemEntity engItemEntity = optional2.get();
            entity.setItemNoEntity(engItemEntity);
        }else {
            throw new BusinessException("子货号 不存在或是无效状态");
        }

        Specification<EngItemEntity> spec3  = (Root<EngItemEntity> root, CriteriaQuery<?> cq, CriteriaBuilder cb) -> {
            Predicate predicate = cb.and(cb.equal(root.get("itemNo"), parentItemNo));
            predicate = cb.and(cb.equal(root.get("status"), 1),predicate);
            predicate = cb.and(cb.equal(root.get("deleted"), 0),predicate);
            return predicate;
        };
        Optional<EngItemEntity> optional3 = engItemRepository.findOne(spec3);
        if(optional3.isPresent()) {
            EngItemEntity engItemEntity = optional3.get();
            entity.setItemNoEntity(engItemEntity);
        }else {
            throw new BusinessException("父货号 不存在或是无效状态");
        }



        SysUserDetails user = SecurityUtils.getUser();
        entity.setCreateBy(user.getUserId());
        entity.setCreateName(user.getUsername());
        entity.setUpdateBy(user.getUserId());
        entity.setUpdateName(user.getUsername());
        entity.setStatus(0);
        repository.save(entity);
    }


    public void update(EngBill2Entity entity){
        // 校验员工编号是否存在
        String parentItemNo = entity.getParentItemNo();
        String childItemNo = entity.getItemNo();
        String ct = entity.getCt();
        Specification<EngBill2Entity> spec  = (Root<EngBill2Entity> root, CriteriaQuery<?> cq, CriteriaBuilder cb) -> {
            Predicate predicate = cb.and(cb.equal(root.get("parentItemNo"), parentItemNo));
            predicate = cb.and(cb.equal(root.get("itemNoEntity").get("itemNo"), childItemNo),predicate);
            predicate = cb.and(cb.equal(root.get("ct"), ct),predicate);
            predicate = cb.and(cb.equal(root.get("deleted"), 0),predicate);
            if(entity.getEngBill2Id()!=null) {
                predicate = cb.and(cb.notEqual(root.get("engBill2Id"), entity.getEngBill2Id()),predicate);
            }
            return predicate;
        };
        long count = repository.count(spec);
        Assert.isTrue(count == 0, "父货号+子类+子货号 已存在");

        //处理关联字段 childItemNo
        Specification<EngItemEntity> spec2  = (Root<EngItemEntity> root, CriteriaQuery<?> cq, CriteriaBuilder cb) -> {
            Predicate predicate = cb.and(cb.equal(root.get("itemNo"), childItemNo));
            predicate = cb.and(cb.equal(root.get("status"), 1),predicate);
            predicate = cb.and(cb.equal(root.get("deleted"), 0),predicate);
            return predicate;
        };
        Optional<EngItemEntity> optional2 = engItemRepository.findOne(spec2);
        if(optional2.isPresent()) {
            EngItemEntity engItemEntity = optional2.get();
            entity.setItemNoEntity(engItemEntity);
        }else {
            throw new BusinessException("子货号 不存在或是无效状态");
        }

        Specification<EngItemEntity> spec3  = (Root<EngItemEntity> root, CriteriaQuery<?> cq, CriteriaBuilder cb) -> {
            Predicate predicate = cb.and(cb.equal(root.get("itemNo"), parentItemNo));
            predicate = cb.and(cb.equal(root.get("status"), 1),predicate);
            predicate = cb.and(cb.equal(root.get("deleted"), 0),predicate);
            return predicate;
        };
        Optional<EngItemEntity> optional3 = engItemRepository.findOne(spec3);
        if(optional3.isPresent()) {
            EngItemEntity engItemEntity = optional3.get();
            entity.setItemNoEntity(engItemEntity);
        }else {
            throw new BusinessException("父货号 不存在或是无效状态");
        }

        repository.save(entity);
    }

    public EngBill2Entity findById(Long id){
        Optional<EngBill2Entity> optional  = repository.findById(id);
        if(optional.isPresent()) {
            EngBill2Entity entity = optional.get();
            EngItemEntity engItemEntity = entity.getItemNoEntity();
            entity.setItemNo(engItemEntity.getItemNo());
            return entity;
        }
        return null;
    }


    public List<EngBill2Entity> findListBy(EngBill2Entity entity){
        // 动态拼接sql
        String hql = " from EngBill2Entity where 1=1";
        if (StringUtils.isNotEmpty(entity.getParentItemNo())  ) {
            hql += " and parentItemNo = '" + entity.getParentItemNo() +"'";
        }
        hql += "  ";
        Query query = em.createQuery(hql);
        List<EngBill2Entity> list = query.getResultList();
        return list;
    }

    public Boolean deleteAllById(String idStrs){
        SysUserDetails user = SecurityUtils.getUser();
        // 逻辑删除
        List<Long> ids = Arrays.asList(idStrs.split(",")).stream()
                .map(idStr -> Long.parseLong(idStr)).collect(Collectors.toList());
        for(Long id:ids) {
            Optional<EngBill2Entity> optional  = repository.findById(id);
            if(optional.isPresent()) {
                EngBill2Entity entity = optional.get();
                entity.setDeleted(1);

                entity.setUpdateBy(user.getUserId());
                entity.setUpdateName(user.getUsername());
                repository.save(entity);
            }
        }
        return true;
    }

}


